﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Kontrolki
{


    public partial class CalendarUC : System.Web.UI.UserControl
    {
        #region private

        private readonly string[] MonthNames = { "Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień" };
        private readonly string[] WeekNames = { "Pon", "Wto", "Śro", "Czw", "Pią", "Sob", "Nie" };
        private const int CellSize = 16;

        public delegate void UserControlRefreshed(object sender, ActionEvent e);
        public event UserControlRefreshed UserControlRefreshedE;

        public enum ActionType
        {
            NextPrevMonth,
            DateSelected,
            PageLoad,
            Unknown
        }
        public class ActionEvent : System.EventArgs
        {
            public ActionType ActionType;

        }
        protected void Page_Load(object sender, EventArgs e)
        {

            if (!this.IsPostBack)
            {
          
                if (UserControlRefreshedE != null)
                    UserControlRefreshedE(null, new ActionEvent() { ActionType = ActionType.PageLoad });
                FulfillCalendar();
            }
            else
            {
                ActionType actionType = ActionType.Unknown;
                if (Request["__EVENTTARGET"] != null && Request["__EVENTARGUMENT"] != null && Request["__EVENTTARGET"] == "UpdatePanel1")
                {
                    string val = Request["__EVENTARGUMENT"];
                    if (val.IndexOf(":") > 0)
                    {
                        if (val.Split(':')[1] != this.ID)
                        {

                            return;
                        }
                        val = val.Split(':')[0];
                    }
                    if (val == null || val == "")
                    {
                    }
                    else
                    {
                        if (val.IndexOf(";") < 0)
                        {
                            if (val.IndexOf("-") < 0)
                            {
                            }
                            else
                            {
                                //mamy foramt 2000-12, oznacza grudzien 2000 roku

                                this.DateStart = new DateTime(int.Parse(val.Split('-')[0]), int.Parse(val.Split('-')[1]), 1);
                                this.ClearSelected();
                                actionType = ActionType.NextPrevMonth;
                            }
                        }
                        else
                        {
                            //mamy foramt 1;12, oznacza to pierwszy grudnia
                            DateTime dt = new DateTime(this.Year, int.Parse(val.Split(';')[1]), int.Parse(val.Split(';')[0]));
                            if (!this.AllowHolidaysChecking && (dt.DayOfWeek == DayOfWeek.Saturday || dt.DayOfWeek == DayOfWeek.Sunday || this.Holidays.Where(a => a == dt).Any()))
                            {

                            }
                            else
                            {
                                int iter = this.GetDayFromBeginning(int.Parse(val.Split(';')[0]), int.Parse(val.Split(';')[1]), this.Year);
                                if (this.hdSelected.Value.Contains("|" + iter + "|"))
                                {
                                    this.hdSelected.Value = this.hdSelected.Value.Replace("|" + iter + "|", "|");
                                }
                                else
                                {
                                    this.hdSelected.Value += iter + "|";
                                }
                                actionType = ActionType.DateSelected;
                            }

                        }
                    }

                }
                if (UserControlRefreshedE != null)
                    UserControlRefreshedE(null, new ActionEvent() { ActionType = actionType });
                if (actionType != ActionType.Unknown)
                {
                    FulfillCalendar();
                }

            }
        }



        private int GetDayFromBeginning(int day, int month, int year)
        {
            DateTime dt = new DateTime(year, month, day);
            return ((int)dt.Subtract(new DateTime(this.Year, 1, 1)).TotalDays + 1);
        }
        private DateTime GetDateFromBeginning(int iterDay, int year)
        {
            return new DateTime(year, 1, 1).AddDays(iterDay - 1);
        }

        protected void cmbYear_SelectedIndexChanged(object sender, EventArgs e)
        {
            //czyścimy
            this.hdSelected.Value = "";

            FulfillCalendar();
        }
        private void FulfillCalendar()
        {
            string[] S = this.hdSelected.Value.Split('|');
            List<int> days = S.Where(a => a.Length > 0).Select(a => int.Parse(a)).OrderBy(a => a).ToList<int>();

            bool selected = false;

            string url = HttpContext.Current.Request.Url.AbsoluteUri;
            DateTime[] h = this.Holidays;
            List<DateTime> na = this.UnavailableDates();
            this.ltl.Text = "<table cellspacing='0'><tr>";
            int Year = this.Year;
            for (int i = this.DateStart.Month; i < (this.NumberOfDisplayedMonths + this.DateStart.Month) && i <= 12; i++)
            {
                int month = (i > 12) ? (i - 12) % 13 : i % 13;
                if (i > 12)
                {
                    Year++;

                }
                if ((i - this.DateStart.Month) == 6)
                {
                    this.ltl.Text += "</tr><tr><td>";
                }
                else
                {
                    this.ltl.Text += "<td>";
                }

                if (this.NumberOfDisplayedMonths == 1)
                {
                    DateTime p = this.DateStart.AddMonths(-1);
                    DateTime n = this.DateStart.AddMonths(1);
                    string prev = "<a href='' style='color:white;text-decoration:none' onclick='return doAJAXPostBack(\"" + p.Year.ToString() + "-" + p.Month.ToString() + ":" + this.ID + "\")'><<</a>";
                    string next = "<a href='' style='color:white;text-decoration:none'  onclick='return doAJAXPostBack(\"" + n.Year.ToString() + "-" + n.Month.ToString() + ":" + this.ID + "\")'>>></a>";
                    this.ltl.Text += "<table class='month'><tr><th> " + prev + " </th><th colspan='5' class='headermonth'>" + MonthNames[month - 1] + " " + Year.ToString() + "</th><th>" + next + "</th></tr>";

                }
                else
                {
                    this.ltl.Text += "<table class='month'><tr><th colspan='7' class='headermonth'>" + MonthNames[month - 1] + "</th></tr>";
                }
                int start = (int)new DateTime(Year, month, 1).DayOfWeek - 1;
                if (start == -1)
                    start = 6;

                int maxDays = DateTime.DaysInMonth(Year, month) + 1;//aby nie od zera
                int current = 1;
                int nextMonth = 1;
                //dni tygodnia
                this.ltl.Text += "<tr>";
                for (int ii = 0; ii < 7; ii++)
                {
                    this.ltl.Text += "<th>" + this.WeekNames[ii] + "</th>";
                }
                this.ltl.Text += "</tr>";
                for (int y = 0; y < 6; y++)
                {
                    this.ltl.Text += "<tr>";
                    for (int x = 0; x < 7; x++)
                    {
                        while (start-- > 0)
                        {
                            this.ltl.Text += AddEmpty(start, month, Year);
                            x++;
                        }
                        if (current < maxDays)
                        {
                            if (days.Count() > 0 && GetDateFromBeginning(days[0], Year) == new DateTime(Year, month, current))
                            {
                                selected = true;
                                days.RemoveAt(0);
                            }
                            //jesli jest niedostepny dodajemy jako pusty
                            if (na.Count() > 0 && na[0] == new DateTime(Year, month, current))
                            {
                                this.ltl.Text += "<td class='empty'>" + current.ToString() + "</td>";
                                na.RemoveAt(0);
                            }
                            else
                            {
                                this.ltl.Text += "<td class='" + (selected ? "selected" : (x == 5 || x == 6 ? "holiday" : (h.Where(a => a.Month == month && a.Day == current && a.Year == Year).Any() ? "holiday" : "none"))) + "'>";
                                if (this.IsDisabled)
                                {
                                    this.ltl.Text += current.ToString();
                                }
                                else
                                {
                                    this.ltl.Text += "<a href='' onclick='return doAJAXPostBack(\"" + current.ToString() + ";" + month + ":" + this.ID + "\")'>" + current.ToString() + "</a>";
                                }
                                this.ltl.Text += "</td>";
                            }
                            selected = false;
                            current++;
                        }
                        else
                        {
                            this.ltl.Text += "<td class='empty'>" + nextMonth.ToString() + "</td>";
                            nextMonth++;
                        }

                    }
                    this.ltl.Text += "</tr>";
                }
                this.ltl.Text += "</table>";
                this.ltl.Text += "</td>";

            }
            this.ltl.Text += "</tr></table>";
        }
        private string AddEmpty(int start, int month, int year)
        {
            int maxDays = new DateTime(year, month, 1).AddDays(-1).Day;
            string result = "<td class='empty'>" + (maxDays - start).ToString() + "</td>";
            return result;
        }



        private int Year
        {
            get
            {

                return DateStart.Year;
            }
        }

        private List<DateTime> UnavailableDates()
        {
            List<DateTime> d = new List<DateTime>();
            if (this.ViewState[this.ID + "UnavailablePeriod"] == null)
            {
                this.ViewState[this.ID + "UnavailablePeriod"] = "|";
            }
            string[] S = this.ViewState[this.ID + "UnavailablePeriod"].ToString().Split('|').Where(a => a.Length > 0).ToArray();
            foreach (string s in S)
            {
                d.Add(this.GetDateFromBeginning(int.Parse(s), this.Year));
            }
            return d.OrderBy(a => a).ToList();

        }
        #endregion

        #region public
        public DateTime[] Selected
        {
            get
            {
                string[] S = this.hdSelected.Value.Split('|');
                return S.Where(a => a.Length > 0).Select(a => int.Parse(a)).OrderBy(a => a).Select(a => this.GetDateFromBeginning(a, this.Year)).ToArray();

            }
            set
            {
                this.hdSelected.Value = "|";

                foreach (DateTime d in value)
                {
                    DateTime begin = new DateTime(d.Year, 1, 1);
                    this.hdSelected.Value += (d.Subtract(begin).TotalDays + 1).ToString() + "|";
                }
                this.FulfillCalendar();

            }
        }
        public DateTime[] Holidays
        {
            get
            {
                string[] S = this.hdHolidays.Value.Split('|');
                return S.Where(a => a.Length > 0).Select(a => int.Parse(a)).OrderBy(a => a).Select(a => this.GetDateFromBeginning(a, this.Year)).ToArray();

            }
            set
            {
                if (this.Year == -1)
                {

                    return;
                }
                this.hdHolidays.Value = "|";

                foreach (DateTime d in value)
                {
                    DateTime begin = new DateTime(d.Year, 1, 1);
                    this.hdHolidays.Value += (d.Subtract(begin).TotalDays + 1).ToString() + "|";
                }
            }
        }
     
        public bool AllowHolidaysChecking
        {
            get
            {
                if (ViewState[this.ID + "AHC"] == null)
                    ViewState[this.ID + "AHC"] = true;
                return bool.Parse(ViewState[this.ID + "AHC"].ToString());
            }
            set
            {
                ViewState[this.ID + "AHC"] = value;
            }
        }
        public void ClearSelected()
        {
            this.hdSelected.Value = "|";
        }
        public void RenderCalendar()
        {
            FulfillCalendar();
        }
        public void AddUnavailablePeriod(DateTime start, DateTime end)
        {
            if (this.ViewState[this.ID + "UnavailablePeriod"] == null)
            {
                this.ViewState[this.ID + "UnavailablePeriod"] = "|";
            }
            while (start <= end)
            {
                int iter = this.GetDayFromBeginning(start.Day, start.Month, start.Year);
                this.ViewState[this.ID + "UnavailablePeriod"] += iter.ToString() + "|";
                start = start.AddDays(1);
            }

        }
        public void ClearUnavailablePeriods()
        {
            this.ViewState[this.ID + "UnavailablePeriod"] = null;

        }
        public bool IsDisabled
        {
            set
            {
                ViewState[this.ID + "IsDisabled"] = value;
            }
            get
            {
                if (ViewState[this.ID + "IsDisabled"] == null)
                    return false;
                else
                    return (bool)ViewState[this.ID + "IsDisabled"];

            }

        }

        public int NumberOfDisplayedMonths
        {
            set
            {
                ViewState[this.ID + "NumberOfDisplayedMonths"] = value;
            }
            get
            {
                if (ViewState[this.ID + "NumberOfDisplayedMonths"] == null)
                    return 12;
                else
                    return (int)ViewState[this.ID + "NumberOfDisplayedMonths"];

            }

        }

        public DateTime DateStart
        {
            set
            {
                ViewState[this.ID + "DateStart"] = value;
            }
            get
            {
                if (ViewState[this.ID + "DateStart"] == null)
                    return DateTime.Now;
                else
                    return DateTime.Parse(ViewState[this.ID + "DateStart"].ToString());

            }

        }
        #endregion
    }
}